#include "datalogger.h"
#include "ses_eeprom.h"
#include "tools/data_utils.h"
#include "ses_lcd.h"
#include "ses_uart.h"

void eeprom_init(){
	ext_eeprom_init();

	// read the first byte in eeprom
	uint8_t status;
	status=0;

	ext_eeprom_read(DATALOGGER_END, &status, sizeof(status));

	if ( status ==1 )
	{
		uint8_t upperStatus, lowerStatus;
		upperStatus=0;
		lowerStatus=0;

		for (uint16_t offset = OFFSET_START+3; offset < OFFSET_END; offset+=4)
		{
			ext_eeprom_read(calc_abs_addr(offset,0), &upperStatus, sizeof(upperStatus));
			ext_eeprom_read(calc_abs_addr(offset,-4), &lowerStatus, sizeof(lowerStatus));


			if (upperStatus ==1 && lowerStatus==0) {

				DATA.stack_offset = ((offset+1) % OFFSET_END);
				uint8_t temp = 0;
				uint16_t co2 = 0;
				ext_eeprom_read(calc_abs_addr(DATALOGGER_START,DATA.stack_offset ),&temp, sizeof(temp));
				DATA.temperature[0] = temp;
				DATA.temperature[1] = temp;
				DATA.temperature[2] = temp;
				DATA.temperature[3] = temp;
				DATA.temperature[4] = temp;
				//TODO get rid of this
				ext_eeprom_read(calc_abs_addr(DATALOGGER_START,DATA.stack_offset +1),(uint8_t*)&co2, sizeof(co2));
				DATA.co2[0] = co2;
				DATA.co2[1] = co2;
				DATA.co2[2] = co2;
				DATA.co2[3] = co2;
				DATA.co2[4] = co2;
				return;
			}
		}
		DATA.stack_offset = OFFSET_START;

	}
	else{
		fprintf(lcdout, "Initialization \n ");
		// the eeprom is never initiated, initiate all the cells to zero, the first byte to 1
		forceInit();

	}

}

void forceInit(){
	//fprintf(uartout, "force init ...\n");

	uint8_t status = FLAG_LAST_STRUCT;
	ext_eeprom_write(DATALOGGER_END, &status, sizeof(uint8_t));

	status = FLAG_END_STRUCT;
	for (uint32_t i = DATALOGGER_START; i < DATALOGGER_END; i++) {
		ext_eeprom_write(i, &status, sizeof(uint8_t));
	}

	DATA.stack_offset = OFFSET_START;
}

void getDataStruct(){
	uint8_t status=6;

	for (uint32_t offset = 0x1000; offset <= 0x1FFF; offset++)
	{
		ext_eeprom_read( offset, &status, sizeof(status));
		fprintf(uartout, "%d:: %d \n",(int)offset, status);

	}

}
/*
 * will be called every 5 seconds
 * @return succesful saving
 */
void save_to_eeprom() {
	//sort

	q_sort8(DATA.temperature,0,4);
	q_sort16(DATA.co2,0,4);

	//get median
	uint8_t medTemp = DATA.temperature[2];
	uint16_t medCO2 =  DATA.co2[2];
	//TODO verify how iniated
	uint16_t offset= DATA.stack_offset;
	uint8_t bottom = 5;

	//save to eeprom avoid recovery status
	if (medCO2 !=0 && medTemp !=0){
		fprintf(uartout," >>>>>>>>>>>>>>>>>>>>>saving  temp %d in %d\n" ,medTemp, calc_abs_addr(offset,0));
		// save temperature
		ext_eeprom_write(calc_abs_addr(offset,0),&medTemp,sizeof(medTemp));

		//save CO2
		ext_eeprom_write(calc_abs_addr(offset,1),(uint8_t*)&medCO2,sizeof(medCO2));

		// set the flag of the last saved struct
		uint8_t last_struct = FLAG_LAST_STRUCT;
		ext_eeprom_write(calc_abs_addr(offset,3),&last_struct,sizeof(uint8_t));


		// set the flag of the previous saved struct
		uint8_t end_struct = FLAG_END_STRUCT;
		ext_eeprom_write(calc_abs_addr(offset,-1),&end_struct,sizeof(uint8_t));

		//	// TODO test
		ext_eeprom_read(calc_abs_addr(offset,-1),&bottom,sizeof(uint8_t));
		ext_eeprom_read(calc_abs_addr(offset,0), (uint8_t *)&medTemp,sizeof(medTemp));
		ext_eeprom_read(calc_abs_addr(offset,1),(uint8_t *)&medCO2,sizeof(medCO2));
		ext_eeprom_read(calc_abs_addr(offset,3),(uint8_t *)&last_struct,sizeof(last_struct));


		//update the new stack offset
		lcd_setCursor(0,2);
		fprintf(lcdout, "%d %d %d %d %d ",DATA.stack_offset,bottom, medTemp, medCO2, last_struct);

		DATA.stack_offset += STRUCT_SIZE;
		DATA.stack_offset %= OFFSET_END;
		fprintf(uartout," >>>>>>>>>>>>>>offset is %d \n", DATA.stack_offset);
	}
	else {
		lcd_setCursor(0,2);
		fprintf(lcdout, "recovery at %d",DATA.stack_offset);
	}

}

uint32_t calc_abs_addr(uint16_t offset, int step) {
	uint16_t temp = (offset + step + OFFSET_END) % OFFSET_END;
	return DATALOGGER_START + temp;
}

void put_temperature(uint8_t temperature) {
	DATA.temp_passes++;
	DATA.temp_passes %= 5;

	fprintf(uartout," new temp added %d to temp[%d]\n" , temperature, DATA.temp_passes);
	DATA.temperature[DATA.temp_passes] = temperature;
}

void put_co2(uint16_t co2) {
	DATA.co2_passes++;
	DATA.co2_passes %= 5;
	fprintf(uartout," new co2 added %d to co2[%d] \n " ,co2, DATA.co2_passes);
	DATA.co2[DATA.co2_passes] = co2;
}

void getAverageValues() {
	uint16_t offset = DATA.stack_offset;
	//uint8_t offset = DATA.stack_offset;
	uint16_t avergCO2 = 0;
	uint16_t co2 = 0;

	uint16_t avergTemp = 0;
	uint8_t temp = 0;

	uint32_t addr = 0;

	// read from eeprom
	fprintf(uartout,"re-extract from offset %d", offset);

	for (int i=-1; i>=-8;i--){
		// read the i-th median temperature
		addr = calc_abs_addr( offset,i*STRUCT_SIZE);
		ext_eeprom_read(addr,&temp,sizeof(uint8_t));
		//fprintf(uartout, "temp=%d from offset %d\n",temp,(int) addr);

		// read the i-th median co2
		addr = calc_abs_addr( offset,i*STRUCT_SIZE+1);
		ext_eeprom_read(addr,(uint8_t *)&co2,sizeof(uint16_t));
		fprintf(uartout,"<<t= %d from %d>>" ,temp, addr);
		avergTemp +=temp;
		avergCO2 +=co2;
	}
	fprintf(uartout," \n >>>>>>>>>>>>>>>>>>>>> finish re-extract \n " );
	avergTemp/=8;
	avergCO2 /=8;
	DATA.avergTemp=avergTemp;
	DATA.avergCO2=avergCO2;

	//	lcd_setCursor(0, 3);
	//		fprintf(lcdout,"t=%d co2=%d",avergTemp, avergTemp);
}
